#include <sys/fcntl.h>
#include <sys/unistd.h>
#include "U2_i2c.h"
#include <errno.h>
#include <sys/ioctl.h>
#include <linux/i2c-dev.h>
#include <linux/i2c.h>
#include <stdio.h>

int i2c_open(char *dev_name)
{
    return open(dev_name, O_RDWR);
}

void i2c_close(int fd)
{
    close(fd);
}

__s32 i2c_smbus_access(int file, char read_write, unsigned char command, int size, union i2c_smbus_data *data)
{
	struct i2c_smbus_ioctl_data args;
	__s32 err;

	args.read_write = read_write;
	args.command = command;
	args.size = size;
	args.data = data;

	err = ioctl(file, I2C_SMBUS, &args);
	if (err == -1)
		err = -errno;
	return err;
}


__s32 i2c_smbus_write_quick(int file, unsigned char value)
{
	return i2c_smbus_access(file, value, 0, I2C_SMBUS_QUICK, NULL);
}

__s32 i2c_smbus_read_byte(int file)
{
	union i2c_smbus_data data;
	int err;

	err = i2c_smbus_access(file, I2C_SMBUS_READ, 0, I2C_SMBUS_BYTE, &data);
	if (err < 0)
		return err;

	return 0x0FF & data.byte;
}


int i2c_detect(int fd, unsigned char *addrArray, int num, unsigned char *addr)
{
	int		ret = -1;

	for(int i=0; i<num; i++)
	{
		if (ioctl(fd, I2C_SLAVE_FORCE, addrArray[i]) < 0)
		{
			continue;
		}
#if 0
		ret = i2c_smbus_write_quick(fd, I2C_SMBUS_WRITE);
#else
		ret = i2c_smbus_read_byte(fd);
#endif
        printf("ret is %d\n", ret);
		if (ret >= 0)
		{
			printf("I2c addr 0X%02X is detected.\n",addrArray[i]);
			*addr = addrArray[i];
			break;
		}
	}

	return ret;
}

int i2c_write_cmd(int fd, unsigned char slave_address, unsigned char cmd)
{
    unsigned char   send_buffer[1];
    struct i2c_rdwr_ioctl_data  package;
    struct i2c_msg  message[1];

    message[0].addr = slave_address;
    message[0].flags = WRITE;
    message[0].len = sizeof(send_buffer);
    message[0].buf = send_buffer;

    send_buffer[0] = cmd;

    package.msgs = message;
    package.nmsgs = 1;

    if (ioctl(fd, I2C_RDWR, &package) < 0)
    {
        return -1;
    }

    return 0;
}

int i2c_write_byte(int fd, unsigned char slave_address, unsigned char reg_address, unsigned char value)
{
    unsigned char send_buffer[2];
    struct i2c_rdwr_ioctl_data package;
    struct i2c_msg message[1];

    message[0].addr = slave_address;
    message[0].flags = WRITE;
    message[0].len = sizeof(send_buffer);
    message[0].buf = send_buffer;

    send_buffer[0] = reg_address;
    send_buffer[1] = value;

    package.msgs = message;
    package.nmsgs = 1;

    if (ioctl(fd, I2C_RDWR, &package) < 0)
    {
        return -1;
    }

    return 0;
}

int i2c_write_bytes(int fd, unsigned char slave_address, unsigned char reg_address, unsigned char *values, int num_byte)
{
    unsigned char send_buffer[2];
    struct i2c_rdwr_ioctl_data package;
    struct i2c_msg message[1];

    message[0].addr = slave_address;
    message[0].flags = WRITE;
    message[0].len = sizeof(send_buffer);
    message[0].buf = send_buffer;

    send_buffer[0] = reg_address;

    package.msgs = message;
    package.nmsgs = 1;

    for (int i = 0; i < num_byte; ++i)
    {
        send_buffer[1] = values[i];
        if (ioctl(fd, I2C_RDWR, &package) < 0)
        {
            return -1;
        }
    }

    return 0;
}

int i2c_read_bytes(int fd, unsigned char slave_address, unsigned char reg_address, unsigned char *buffer, int num_byte)
{
    unsigned char send_buffer[1];
    struct i2c_rdwr_ioctl_data package;
    struct i2c_msg messages[2];

    messages[0].addr = slave_address;
    messages[0].flags = WRITE;
    messages[0].len = sizeof(send_buffer);
    messages[0].buf = send_buffer;

    send_buffer[0] = reg_address;

    messages[1].addr = slave_address;
    messages[1].flags = READ;
    messages[1].len = num_byte;
    messages[1].buf = buffer;

    package.msgs = messages;
    package.nmsgs = 2;

    ioctl(fd, I2C_TIMEOUT, 2);
    ioctl(fd, I2C_RETRIES, 1);

    if (ioctl(fd, I2C_RDWR, &package) < 0)
    {
        return -1;
    }

    return 0;
}

int i2c_read_bytes_16addr(int fd, unsigned char slave_address, __u16 reg_address, unsigned char *buffer, int num_byte)
{
    unsigned char send_buffer[2];
    struct i2c_rdwr_ioctl_data package;
    struct i2c_msg messages[2];

    send_buffer[0] = (reg_address >> 8) & 0xFF;
    send_buffer[1] = reg_address & 0xFF;

    messages[0].addr = slave_address;
    messages[0].flags = WRITE;
    messages[0].len = sizeof(send_buffer);
    messages[0].buf = send_buffer;

    messages[1].addr = slave_address;
    messages[1].flags = READ;
    messages[1].len = num_byte;
    messages[1].buf = buffer;

    package.msgs = messages;
    package.nmsgs = 2;

    ioctl(fd, I2C_TIMEOUT, 2);
    ioctl(fd, I2C_RETRIES, 1);

    if (ioctl(fd, I2C_RDWR, &package) < 0)
    {
        return -1;
    }

    return 0;
}